package org.common.users.intercepter;

import org.common.users.annotation.RepeatRequest;
import org.common.users.exception.RepeatRequestException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 自定义重复提交拦截器
 *
 * @author samphin
 * @since 2020-7-17 10:41:05
 */
public class AnnotationTokenInterceptor extends HandlerInterceptorAdapter {

    private static final Logger logger = LoggerFactory.getLogger(AnnotationTokenInterceptor.class);

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response, Object handler) throws Exception {
        //如果没有映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //获取注解
        RepeatRequest annotation = method.getAnnotation(RepeatRequest.class);
        //如果没有注解，直接通过
        if (annotation == null) {
            return true;
        }
        //获取注解repeat
        boolean needrepeat = annotation.repeat();
        //如果需要防重发，在redis中添加计数器
        if (needrepeat) {
            String uuid = UUID.randomUUID().toString();
            String key = "data_v_" + uuid;
            System.out.println("uuid:" + uuid);
            redisTemplate.opsForValue().set(key, "1", 60 * 60, TimeUnit.SECONDS);
            response.addHeader("data_v", uuid);
            logger.warn(request.getServletPath() + "---->from data_v_:" + uuid);
        }
        //获取注解checkRepeat,第一次提交则去掉token,并允许交易通过，重复提交则不允许交易通过
        boolean needCheckRepeat = annotation.check();
        if (needCheckRepeat) {
            if (isRepeatSubmit(request)) {
                throw new RepeatRequestException("请不要重复提交哦!!!!,url:" + request.getServletPath());
            }
        }
        return true;
    }


    /**
     * 验证同一个url数据是否相同提交 ,相同返回true
     *
     * @param request
     * @return
     * @throws Exception
     */
    private boolean isRepeatSubmit(HttpServletRequest request) {
        //从请求头获取请求token值
        String token = request.getHeader("data_v");
        //检查redis中是否存在该用户的token
        boolean isExist = redisTemplate.hasKey("data_v_" + token);
        //用户token减一，如果等于0，则是第一次提交
        if(isExist){
            Long count = redisTemplate.opsForValue().decrement("data_v_" + token, 1);
            if (count == 0) {
                //删除用户token
                redisTemplate.delete("data_v_" + token);
                return false;
            }
        }
        return true;
    }

}
